using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Gj_sparrow.Framework.Services;
using Gj.Galaxy.Logic;
using Gj.MapData;
using Gj.MapData.Strategy;
using MessagePack;
using Unity.Entities;
using UnityEngine;
using WebSocketSharp;
using Random = System.Random;

namespace Gj
{
    // TODO待处理， 是否需要删除
    [Serializable]
    public class RefInfo
    {
        public int id;
        public string key;
        public string name;

        public override string ToString()
        {
            return string.Format("RefInfo: ref->{0} name->{1}", key.IsNullOrEmpty() ? id.ToString() : key, name);
        }
    }

    public interface ClearObject
    {
        void Clear();
    }

    public interface DefineLoadResource
    {
        void LoadResource(string name, byte[] data);
    }

    public interface AttrDataManager
    {
        int AttrIndex(int id);
        int AttrIndex(string key);
        int AttrLength();

        byte DataIndex(int attrIndex);
        byte DataIndex(string key);
        int DataLength();
        string[] DataKeys();
        int[] DataIndexs();
    }

    public enum HexD
    {
        Up = 0,
        UpLeft = 1,
        DownLeft = 2,
        Down = 3,
        DownRight = 4,
        UpRight = 5
    }

    public interface CoreObject
    {
        bool IsAuto();
        bool IsExist();
        int GetIndex();
        object GetId();
        Entity GetEntity();
        string GetName();
        string GetKey();
    }

    public interface UnityObject : CoreObject
    {
        float GetRadius();
        float GetHeight();
        Vector3 GetPosition();
        Quaternion GetRotation();
        void SetPosition(Vector3 position);
        void SetRotation(Quaternion rotation);
        void UpdatePosition(Vector3 position);
        void UpdateRotation(Quaternion rotation);
        GameObject GetGameObject();
    }

    public interface AttrObject
    {
        ObjectAttrInf GetAttr();
    }

    public interface DataObject : CoreObject, AttrObject
    {
        bool IsEnemy(DataObject obj);
        bool IsPartner(DataObject obj);
        int GetIdentity();
    }

    public interface RealObject : UnityObject
    {
        bool IsDebug();
        DataObject GetData();
        int GetTotal();
        int GetNumber();
        Skin GetObject();
        Skin GetObject(int index);
        Vector3 GetRealPosition();
        Quaternion GetRealRotation();
    }

    public interface SyncObject
    {
        NetworkEsse GetSync();
    }

    public interface DefineObject
    {
        DefineData GetDefineData();
        IdentityData GetIdentityData();
        Vector2Int GetNode();
    }

    public interface SelectObject
    {
        void Select();
        void Cancel();
    }

    public interface SignObject
    {
        void Open();
        void Close();
    }

    public interface Element : RealObject, DefineObject, SelectObject
    {
        void Recovery();
        void Show();
        void Hide();
        void Log(string key);
    }

    public interface Logic
    {
        bool IsActive();
        int GetIndex();
    }

    public interface ElementLogic
    {
        void Init(Logic logic);
        void Destroy();
    }

    public interface Control : DataObject, SyncObject, RealObject
    {
        Control GetMaster();
        bool IsPlayer();
        void OnReady();
        void OnFinish();

        void OnMessage(Control obj, byte type, byte category, int value);
        // 获取网络同步组件
    }

    public class ControlFormatter : SerializeFormatter
    {
        internal static readonly ControlFormatter instance = new();

        public object Deserialize(byte[] stream)
        {
            var ID = MessagePackSerializer.Deserialize<uint>(stream);
            //            var ID = BitConverter.ToInt64(stream, 0);
            var esse = SyncService.Get(ID);
            return esse != null ? esse.GetSyncObject() : null;
        }

        public byte[] Serialize(object customobject)
        {
            var control = (Control)customobject;
            return MessagePackSerializer.Serialize(control.GetSync().hash);
        }
    }

    public interface Move : RealObject
    {
        float GetMoveSpeedTime();
        float GetMoveSpeed();
        float GetRotateSpeed();
        void OnMoveStart();
        void OnMoveStop();
        float GetKeepRadius();
    }

    public interface Life : RealObject
    {
        bool IsLive();
        void Birth();
        void Die();
        GameObject GetHit(Cast cast);
        GameObject GetHit(int index, Cast cast);
        void OnSkill(DataObject obj, Skill skill, float power, int time);
        void OnBuff(DataObject obj, Buff buff, int time);
        // void OnMove(DataObject obj, Skill skill, Vector3 position);
        void OnChange(DataObject obj, Change change);
        void OnChange(Cast cast, Change change);
        void SignChange(Cast cast, Skill skill, int i);
    }

    public interface Cast : RealObject
    {
        float GetCastTime(Skill skill);
        float GetCoolTime(Skill skill);

        float GetCastRadius();

        // 检查是否满足施放条件
        bool OnInspect(Skill skill, int time);

        // 施放完毕消耗
        void OnConsume(Skill skill, int time);
        // void OnHit(Skill skill, int time);
        // void OnChange(Change change);
        bool OnCheckChange(Change change);
        CastSkin GetCastObject();
        CastSkin GetCastObject(int index);
    }

    public enum ChangeType : byte
    {
        None = 0,
        AddAttr = 1,
        SubAttr = 2,
        AddBuff = 3,
        ClearBuff = 4,
        AddHealth = 5,
        SubHealth = 6,
        ChangeAttr = 7,
        AddPower = 8,
        SubPower = 9,
    }

    public class Change : ClearObject
    {
        internal static ConcurrentQueue<Change> queue = new();
        public int index;
        public List<int> specialList;
        public int times;
        public ChangeType type;
        public int value;
        public int[] values;

        public void Clear()
        {
            specialList.Clear();
            values = null;
            queue.Enqueue(this);
            times = 0;
        }

        public static Change Make()
        {
            Change change = null;
            if (queue.TryDequeue(out change))
            {
            }

            if (change == null)
            {
                change = new Change();
                change.specialList = new List<int>();
                change.times = 0;
            }

            return change;
        }

        public static Change Parse(object[] data)
        {
            var change = Make();
            change.index = Convert.ToInt32(data[0]);
            change.type = (ChangeType)Convert.ToByte(data[1]);
            if (data[2] != null)
            {
                var special = (object[])data[2];
                change.specialList = new List<int>();
                for (var i = 0; i < special.Length; i++) change.specialList.Add(Convert.ToInt32(special[i]));
            }

            if (data[3] != null)
            {
                var value = (object[])data[3];
                change.values = new int[value.Length];
                for (var i = 0; i < value.Length; i++)
                {
                    change.values[i] = Convert.ToInt32(value[i]);
                    change.value += change.values[i];
                }

                change.value = change.values[0];
            }

            return change;
        }

        public void Bind(ChangeType type, int value, int index)
        {
            this.value = value;
            this.index = index;
            this.type = type;
        }

        public override string ToString()
        {
            return string.Format("Change: type->{0} value->{1} index->{2} special->{3}", type, value, index, specialList.Count > 0 ? specialList[0] : "-");
        }

        public object Object()
        {
            if (values == null) values = new[] { value };
            return new object[] { index, (byte)type, specialList.ToArray(), values };
        }
    }

    public struct LifeChange
    {
        public Life target;
        public Change[] changes;

        public override string ToString()
        {
            if (changes == null) return "Life Change Empty!";
            string s = "Life Change: ";
            for (int i = 0; i < changes.Length; i++)
            {
                s += changes[i].ToString();
            }
            return s;
        }
    }

    public interface GameService
    {
        void OnInit();
        void OnUpdate();
        void OnDestroy();
    }

    public interface GameManager
    {
        void OnInit();
        Task OnUpdate();
        void OnDestroy();
        void OnPage(BasePage page);
    }

    public interface GamePlugin : GameListener, GameReadyListener, BroadcastListener, TimeListener
    {
        void OnInit(BaseGameSpace space);
        void OnDestroy();
        GameService[] GetRequireService();
        void OnUpdate();
    }

    public interface MobilePlayerControl
    {
        void LeftRockerEnter();

        void LeftRocker(float angle, float h, float v);

        void LeftRockerExit();

        void RightRockerEnter();

        void RightRocker(float angle, float h, float v);

        void RightRockerExit();
    }

    public interface Skin
    {
        float GetRadius();
        float GetHeight();
        void SetRotation(Quaternion rotation);
        void SetPosition(Vector3 position);
        Quaternion GetRotation();
        Vector3 GetPosition();
        void Show();
        void Hide();
        string GetKey();
        GameObject GetGameObject();
    }

    public interface CastSkin: Skin
    {
        void LookAt(Vector3 position);
        void SetAngle(float angle);
        GameObject GetOrigin(Skill skill);
    }

    public interface LifeSkin: Skin
    {
    }

    public enum GROUP : byte
    {
        ID,
        KEY
    }

    [Serializable]
    public class Group
    {
        public int Id;
        public string Key;

        public Group(object[] objects)
        {
            if (objects == null) return;
            Id = Convert.ToInt32(objects[(byte)GROUP.ID]);
            Key = Convert.ToString(objects[(byte)GROUP.KEY]);
        }
    }

    public enum BASE_INFO : byte
    {
        HEIGHT,
        SCALE,
        COLLIDER,
        RADIUS,
        SIZEX,
        SIZEY,
        SIZEZ,
        CENTERX,
        CENTERY,
        CENTERZ,
        TRIGGER,
        RIGIDBODY,
        GRAVITY,
        KINEMATIC,
        SPEED,
        ROTATE
    }

    [Serializable]
    public class BaseInfo
    {
        public float height;
        public float scale;
        public ObjectCollider collider;
        public float radius;
        public float sizeX;
        public float sizeY;
        public float sizeZ;
        public float centerX;
        public float centerY;
        public float centerZ;
        public bool trigger;
        public bool rigidbody;
        public bool gravity;
        public bool kinematic;
        public float speed;
        public float rotate;

        public BaseInfo(object[] objects)
        {
            if (objects == null) return;
            height = (float)objects[(byte)BASE_INFO.HEIGHT];
            scale = (float)objects[(byte)BASE_INFO.SCALE];
            sizeX = (float)objects[(byte)BASE_INFO.SIZEX];
            collider = (ObjectCollider)Convert.ToInt32(objects[(byte)BASE_INFO.COLLIDER]);
            radius = (float)objects[(byte)BASE_INFO.RADIUS];
            sizeX = (float)objects[(byte)BASE_INFO.SIZEX];
            sizeY = (float)objects[(byte)BASE_INFO.SIZEY];
            sizeZ = (float)objects[(byte)BASE_INFO.SIZEZ];
            centerX = (float)objects[(byte)BASE_INFO.CENTERX];
            centerY = (float)objects[(byte)BASE_INFO.CENTERY];
            centerZ = (float)objects[(byte)BASE_INFO.CENTERZ];
            trigger = Convert.ToBoolean(objects[(byte)BASE_INFO.TRIGGER]);
            rigidbody = Convert.ToBoolean(objects[(byte)BASE_INFO.RIGIDBODY]);
            gravity = Convert.ToBoolean(objects[(byte)BASE_INFO.GRAVITY]);
            kinematic = Convert.ToBoolean(objects[(byte)BASE_INFO.KINEMATIC]);
            speed = (float)objects[(byte)BASE_INFO.SPEED];
            rotate = (float)objects[(byte)BASE_INFO.ROTATE];
        }

        public override string ToString()
        {
            return string.Format(
                "BaseInfo: collider->{0} radius->{1} height->{2} sizeX->{3} sizeY->{4} sizeZ->{5} centerX->{6} centerY->{7} centerZ->{8} " +
                "trigger->{8} rigidbody->{9} gravity->{10} kinematic->{11} speed->{12} rotate->{14}", collider, radius,
                height, sizeX, sizeY, sizeZ, centerX, centerY, centerZ, trigger, rigidbody, gravity, kinematic, speed,
                rotate);
        }

        public object[] ToObject()
        {
            return new object[]
            {
                collider, radius, height, sizeX, sizeY, sizeY, centerX, centerY, centerZ, trigger, rigidbody, gravity,
                kinematic, speed, rotate
            };
        }
    }

    public interface ObjectAttrInf
    {
        int GetWithId(int i);
        void SetWithId(int id, int value);
        int GetWithIndex(int i);
        void SetWithIndex(int id, int value);
        AttrManager Manager();
    }

    [Serializable]
    public class ObjectAttr : ObjectAttrInf
    {
        [SerializeField] private int[] real;

        internal AttrManager _manager;

        public ObjectAttr(AttrManager manager)
        {
            _manager = manager;
            real = new int[manager.AttrLength()];
        }

        public ObjectAttr(object[] objects, AttrManager manager)
        {
            _manager = manager;
            real = new int[manager.AttrLength()];
            foreach (var index in manager.BattleIndexs())
            {
                var attr = manager.GetAttr(index);
                if (attr.Default != 0)
                    // Debug.LogError("attr default"+index+":"+attr.refInfo.id+"->"+attr.Default);
                    real[index] = attr.Default;
            }

            if (objects == null) return;

            for (var i = 0; i < objects.Length; i += 2)
            {
                var id = Convert.ToInt32(objects[i]);
                var index = manager.AttrIndex(id);
                if (index < 0) continue;
                real[index] = Convert.ToInt32(objects[i + 1]);
                // Debug.LogError("attr:" + id + "; index:" + manager.AttrIndex(id) + ":" + real[manager.AttrIndex(id)]);
            }
        }

        public ObjectAttr(int[] objects, AttrManager manager)
        {
            _manager = manager;
            real = new int[manager.AttrLength()];
            foreach (var index in manager.BattleIndexs())
            {
                var attr = manager.GetAttr(index);
                if (attr.Default != 0)
                    // Debug.LogError("attr default"+index+":"+attr.refInfo.id+"->"+attr.Default);
                    real[index] = attr.Default;
            }

            if (objects == null) return;
            for (var i = 0; i < objects.Length; i += 2)
            {
                // Debug.LogError(objects[i]+":"+manager.AttrIndex(objects[i]));
                var index = manager.AttrIndex(objects[i]);
                if (index < 0) continue;
                real[index] = objects[i + 1];
            }
        }

        public ObjectAttr(ObjectAttr attr)
        {
            real = new int[attr.length];
            _manager = attr._manager;
            attr.CopyTo(real);
        }

        public int this[int index]
        {
            get => Get(index);
            set => Set(index, value);
        }

        public int this[string key]
        {
            get => Get(key);
            set => Set(key, value);
        }

        public int length => real.Length;

        public int GetWithId(int i)
        {
            var ii = _manager.AttrIndex(i);
            // Debug.LogError("Get with id:"+i+"->"+ii+"="+Get(ii));

            return GetWithIndex(ii);
        }

        public void SetWithId(int i, int v)
        {
            var ii = _manager.AttrIndex(i);
            SetWithIndex(ii, v);
        }

        public int GetWithIndex(int i)
        {
            if (i > length - 1 || i < 0)
            {
                Debug.LogError("ObjectBattleAttr " + i + " not exist");
                return 0;
            }

            return real[i];
        }

        public void SetWithIndex(int i, int v)
        {
            if (i > length - 1 || i < 0)
            {
                Debug.LogError("ObjectBattleAttr " + i + " not exist");
                return;
            }

            real[i] = v;
        }

        public AttrManager Manager()
        {
            return _manager;
        }

        public int[] Object()
        {
            var list = new List<int>();
            for (var i = 0; i < real.Length; i++)
            {
                if (real[i] == 0) continue;
                list.Add(_manager.AttrId(i));
                list.Add(real[i]);
            }

            return list.ToArray();
        }

        public int Get(int i)
        {
            return GetWithIndex(i);
        }

        public void Merge(ObjectAttr attr)
        {
            for (var i = 0; i < attr.real.Length; i++)
            {
                if (attr.real[i] == 0) continue;
                // Debug.LogError("merge atttr:"+i+"->"+attr.real[i]);
                // SetWithIndex(i, GetWithIndex(i) + attr.real[i]);
                real[i] += attr.real[i];
            }
        }

        public void SetId(int i, int v)
        {
            SetWithIndex(_manager.AttrIndex(i), v);
        }
        public void GetId(int i, int v)
        {
            SetWithIndex(_manager.AttrIndex(i), v);
        }
        public void Set(int i, int v)
        {
            SetWithIndex(i, v);
        }

        public int Get(string key)
        {
            return GetWithIndex(_manager.AttrIndex(key));
        }

        public void Set(string key, int v)
        {
            SetWithIndex(_manager.AttrIndex(key), v);
        }

        public void CopyFrom(ObjectAttr attr)
        {
            attr.real.CopyTo(real, 0);
        }
        public void CopyFrom(int[] tmp)
        {
            tmp.CopyTo(real, 0);
        }

        public void CopyTo(ObjectAttr attr)
        {
            real.CopyTo(attr.real, 0);
        }
        public void CopyTo(int[] tmp)
        {
            real.CopyTo(tmp, 0);
        }

        public void Clear()
        {
            for (var i = 0; i < real.Length; i++)
            {
                real[i] = 0;
            }
        }

        public int[] Data()
        {
            return real;
        }

        public override string ToString()
        {
            var s = "";
            for (var i = 0; i < real.Length; i++) s += string.Format("[{0}:{1}]", i, real[i]);
            return string.Format("attr->{0}", s);
        }
    }

    [Serializable]
    public class ObjectBattleAttr : ObjectAttrInf
    {
        [SerializeField] private int[] real;

        internal AttrManager _manager;

        public ObjectBattleAttr(AttrManager manager)
        {
            _manager = manager;
            real = new int[manager.BattleLength()];
        }

        public ObjectBattleAttr(object[] objects, AttrManager manager)
        {
            _manager = manager;
            real = new int[manager.BattleLength()];
            foreach (var index in manager.BattleIndexs())
            {
                var attr = manager.GetAttr(index);
                if (attr.Default != 0)
                    // Debug.LogError("attr default"+index+":"+attr.refInfo.id+"->"+attr.Default);
                    real[manager.BattleFromIndex(index)] = attr.Default;
            }

            if (objects == null) return;

            for (var i = 0; i < objects.Length; i += 2)
            {
                var id = Convert.ToInt32(objects[i]);
                var index = manager.BattleIndex(id);
                if (index < 0) continue;
                real[index] = Convert.ToInt32(objects[i + 1]);
                // Debug.LogError("attr:" + id + "; index:" + manager.AttrIndex(id) + ":" + real[manager.AttrIndex(id)]);
            }
        }

        public ObjectBattleAttr(int[] objects, AttrManager manager)
        {
            _manager = manager;
            real = new int[manager.BattleLength()];
            foreach (var index in manager.BattleIndexs())
            {
                var attr = manager.GetAttr(index);
                if (attr.Default != 0)
                {
                    // Debug.LogError("attr default"+index+":"+attr.refInfo.id+"->"+attr.Default);
                    real[manager.BattleFromIndex(index)] = attr.Default;
                }
            }

            if (objects == null) return;
            for (var i = 0; i < objects.Length; i += 2)
            {
                // Debug.LogError("battle attr:"+objects[i]+":"+manager.BattleIndex(objects[i])+"="+objects[i + 1]);
                var index = manager.BattleIndex(objects[i]);
                if (index < 0) continue;
                real[index] = objects[i + 1];
            }
        }

        public ObjectBattleAttr(ObjectBattleAttr attr)
        {
            real = new int[attr.length];
            _manager = attr._manager;
            attr.CopyTo(real);
        }

        public int this[int index]
        {
            get => Get(index);
            set => Set(index, value);
        }

        public int this[string key]
        {
            get => Get(key);
            set => Set(key, value);
        }

        public int length => real.Length;

        public int GetWithId(int i)
        {
            var ii = _manager.BattleIndex(i);
            // Debug.LogError("Get with id:"+i+"->"+ii+"="+Get(ii));

            return Get(ii);
        }

        public void SetWithId(int i, int v)
        {
            var ii = _manager.BattleIndex(i);
            Set(ii, v);
        }

        public int GetWithIndex(int i)
        {
            var ii = _manager.BattleFromIndex(i);
            return Get(ii);
        }

        public void SetWithIndex(int i, int v)
        {
            var ii = _manager.BattleFromIndex(i);
            Set(ii, v);
        }

        public AttrManager Manager()
        {
            return _manager;
        }

        public int[] Object()
        {
            var list = new List<int>();
            for (var i = 0; i < real.Length; i++)
            {
                if (real[i] == 0) continue;
                list.Add(_manager.AttrIdFromBattle(i));
                list.Add(real[i]);
            }

            return list.ToArray();
        }

        public int Get(int i)
        {
            if (i > length - 1 || i < 0)
            {
                Debug.LogError("ObjectAttr " + i + " not exist");
                return 0;
            }

            return real[i];
        }

        public void Set(int i, int v)
        {
            if (i > length - 1 || i < 0)
            {
                Debug.LogError("ObjectAttr " + i + " not exist");
                return;
            }

            real[i] = v;
        }

        public int Get(string key)
        {
            return Get(_manager.BattleIndex(key));
        }

        public void Set(string key, int v)
        {
            Set(_manager.BattleIndex(key), v);
        }

        public void CopyFrom(ObjectAttr attr)
        {
            attr.CopyTo(real);
        }

        public void CopyTo(int[] tmp)
        {
            real.CopyTo(tmp, real.Length);
        }

        public int[] Data()
        {
            return real;
        }

        public override string ToString()
        {
            var s = "";
            for (var i = 0; i < real.Length; i++) s += string.Format("[{0}:{1}]", i, real[i]);
            return string.Format("attr->{0}", s);
        }
    }

    public class ObjectData
    {
        private readonly ObjectAttr _attr;
        private readonly int[] _indexs;
        private readonly AttrDataManager _manager;

        public ObjectData(ObjectAttr attr, AttrDataManager manager)
        {
            _manager = manager;
            _attr = attr;
            _indexs = manager.DataIndexs();
        }

        public int this[int index]
        {
            get => Get(index);
            set => Set(index, value);
        }

        public int this[string key]
        {
            get => Get(key);
            set => Set(key, value);
        }

        public int length => _indexs.Length;

        public int Get(int i)
        {
            if (i >= length)
            {
                Debug.LogError("ObjectData " + i + " not exist");
                return 0;
            }

            return _attr[_indexs[i]];
        }

        public void Set(int i, int v)
        {
            if (i >= _indexs.Length)
            {
                Debug.LogError("ObjectData " + i + " not exist");
                return;
            }

            _attr[_indexs[i]] = v;
        }

        public int Get(string key)
        {
            return Get(_attr._manager.AttrIndex(key));
        }

        public void Set(string key, int v)
        {
            Set(_attr._manager.AttrIndex(key), v);
        }

        public string[] DataKeys()
        {
            return _manager.DataKeys();
        }

        public int[] DataIndexs()
        {
            return _manager.DataIndexs();
        }

        public int DataLength()
        {
            return _manager.DataLength();
        }

        public override string ToString()
        {
            var s = "";
            for (var i = 0; i < _indexs.Length; i++) s += string.Format("[{0}:{1}]", i, Get(i));
            return string.Format("data->{0}", s);
        }
    }

    public enum OBJECT_INFO : byte
    {
        ID,
        NAME,
        CATEGORY,
        IDENTITY,
        SKIN,
        BASE,
        LIVE_TIME,
        ATTR,
        EXTEND,
        AI,
        ATTR_EVENT
    }

    [Serializable]
    public class ObjectInfo
    {
        [RefField("object")] public RefInfo refInfo;
        public int category;
        public int identity;
        public string skin;
        public BaseInfo baseInfo;
        public int liveTime;
        public AttrEventList attrEvent;
        public object[] ai;
        public object[] attr;
        public object[] extend;

        public ObjectInfo(object[] objects)
        {
            refInfo = new RefInfo();
            refInfo.id = Convert.ToInt32(objects[(byte)OBJECT_INFO.ID]);
            refInfo.name = (string)objects[(byte)OBJECT_INFO.NAME];
            category = Convert.ToInt32(objects[(byte)OBJECT_INFO.CATEGORY]);
            identity = Convert.ToInt32(objects[(byte)OBJECT_INFO.IDENTITY]);
            skin = (string)objects[(byte)OBJECT_INFO.SKIN];
            baseInfo = new BaseInfo((object[])objects[(byte)OBJECT_INFO.BASE]);
            liveTime = Convert.ToInt32(objects[(byte)OBJECT_INFO.LIVE_TIME]);
            if (objects[(byte)OBJECT_INFO.ATTR] != null) attr = (object[])objects[(byte)OBJECT_INFO.ATTR];
            if (objects[(byte)OBJECT_INFO.EXTEND] != null) extend = (object[])objects[(byte)OBJECT_INFO.EXTEND];
            if (objects[(byte)OBJECT_INFO.AI] != null) ai = (object[])objects[(byte)OBJECT_INFO.AI];
            if (objects[(byte)OBJECT_INFO.ATTR_EVENT] != null)
                attrEvent = new AttrEventList((object[])objects[(byte)OBJECT_INFO.ATTR_EVENT]);
        }

        public override string ToString()
        {
            return string.Format(
                "ObjectInfo:{0} name->{1} baseInfo->{2} category->{3} identity->{4} skin->{5} attr->{6} extend->{7} ai->{8}",
                refInfo.id, refInfo.name, baseInfo, category, identity, skin, attr, extend, ai);
        }

        public object[] ToObject()
        {
            return new object[]
            {
                refInfo.id, refInfo.name, category, identity, skin, baseInfo.ToObject(), liveTime, attr, extend, ai,
                attrEvent.ToObject()
            };
        }
    }

    public struct Status
    {
        public override string ToString()
        {
            return string.Format("Status: ing->{0} time->{1} buff->{2} number->{3} obj->{4} lastTime->{4}", ing, time,
                buff, number, cast, lastTime);
        }

        public bool ing;
        public int lastTime;
        public int time;
        public Buff buff;
        public int number;
        public DataObject cast;

        public void Next(int time)
        {
            lastTime = time + buff.intervalTime;
        }
    }

    public class StatusFormatter : SerializeFormatter
    {
        internal static readonly BuffFormatter buffFormatter = BuffFormatter.instance;
        internal static readonly ControlFormatter castFormatter = ControlFormatter.instance;
        internal static readonly StatusFormatter instance = new();
        private readonly object[] tmp = new object[4];

        public object Deserialize(byte[] stream)
        {
            var info = MessagePackSerializer.Deserialize<object[]>(stream);
            var status = new Status();
            status.time = Convert.ToInt32(info[0]);
            status.buff = (Buff)buffFormatter.Deserialize((byte[])info[1]);
            status.cast = (DataObject)castFormatter.Deserialize((byte[])info[2]);
            status.number = Convert.ToInt32(info[3]);
            return status;
        }

        public byte[] Serialize(object customobject)
        {
            var status = (Status)customobject;
            tmp[0] = status.time;
            tmp[1] = buffFormatter.Serialize(status.buff);
            tmp[2] = castFormatter.Serialize(status.cast);
            tmp[3] = status.number;
            return MessagePackSerializer.Serialize(tmp);
        }
    }

    public enum AttrInfoType : byte
    {
        BOOL,
        PERCENT,
        NUMBER
    }

    public enum ATTR_INFO : byte
    {
        ID,
        TYPE,
        KEY,
        IS_DATA,
        IS_BATTLE,
        DEFAULT
    }

    [Serializable]
    public class AttrInfo
    {
        [RefField("attr")] public RefInfo refInfo;
        public AttrInfoType type;
        public bool isData;
        public bool isBattle;
        public int Default;

        public AttrInfo(object[] objects)
        {
            refInfo = new RefInfo();
            refInfo.id = Convert.ToInt32(objects[(byte)ATTR_INFO.ID]);
            refInfo.key = Convert.ToString(objects[(byte)ATTR_INFO.KEY]);
            type = (AttrInfoType)objects[(byte)ATTR_INFO.TYPE];
            isData = Convert.ToBoolean(objects[(byte)ATTR_INFO.IS_DATA]);
            isBattle = Convert.ToBoolean(objects[(byte)ATTR_INFO.IS_BATTLE]);
            Default = Convert.ToInt32(objects[(byte)ATTR_INFO.DEFAULT]);
        }

        public int Compute(int value, Random random)
        {
            switch (type)
            {
                case AttrInfoType.BOOL:
                    return value > 0 ? 1 : 0;
                case AttrInfoType.PERCENT:
                    return UnityTools.IsOk(random, value) ? 1 : 0;
            }

            return value;
        }

        public override string ToString()
        {
            return string.Format("AttrInfo:{0} type->{1}", refInfo, type);
        }

        public object[] ToObject()
        {
            return new object[] { refInfo.id, type };
        }
    }

    public enum ATTR_GROUP : byte
    {
        ID,
        TYPE,
        VAR_LENGTH,
        LOGIC_LIST
    }


    [Serializable]
    public class AttrGroup
    {
        [RefField("attr_logic_group")] public RefInfo refInfo;
        public byte type;
        public byte varLength;
        public AttrLogicList logicList;

        public AttrGroup(object[] objects)
        {
            refInfo = new RefInfo();
            refInfo.id = Convert.ToInt32(objects[(byte)ATTR_GROUP.ID]);
            type = (byte)objects[(byte)ATTR_GROUP.TYPE];
            varLength = (byte)objects[(byte)ATTR_GROUP.VAR_LENGTH];
            logicList = new AttrLogicList((object[])objects[(byte)ATTR_GROUP.LOGIC_LIST]);
        }

        public override string ToString()
        {
            return string.Format("AttrLogicGroup:{0} type->{1} logicList->{2}",
                refInfo, type, logicList);
        }

        public object[] ToObject()
        {
            return new object[] { refInfo.id, type, logicList };
        }
    }

    public enum AttrConditionCompute : byte
    {
        EQUAL = 0,
        GREATER = 1,
        LESS = 2,
        GREATER_EQUAL = 3,
        LESS_EQUAL = 4,
        MULTIPLE = 5,
        EQUAL_VAR = 6,
        GREATER_VAR = 7,
        LESS_VAR = 8,
        GREATER_EQUAL_VAR = 9,
        LESS_EQUAL_VAR = 10,
        MULTIPLE_VAR = 11,
        NO_EQUAL_VAR = 12,
        NO_EQUAL = 13,
    }

    public enum AttrConditionTarget : byte
    {
        First = 0,
        Second = 1,
        Var = 2,
        VarPercent = 3
    }

    public enum ATTR_CONDITION : byte
    {
        TARGET,
        INDEX,
        COMPUTE,
        VALUE
    }

    [Serializable]
    public class AttrCondition
    {
        public AttrConditionTarget target;
        public byte index;
        public AttrConditionCompute compute;
        public int value;

        public AttrCondition(object[] objects)
        {
            target = (AttrConditionTarget)objects[(byte)ATTR_CONDITION.TARGET];
            index = (byte)objects[(byte)ATTR_CONDITION.INDEX];
            compute = (AttrConditionCompute)objects[(byte)ATTR_CONDITION.COMPUTE];
            value = Convert.ToInt32(objects[(byte)ATTR_CONDITION.VALUE]);
        }

        public bool Compute(int[] vars, int v)
        {
            switch (compute)
            {
                case AttrConditionCompute.EQUAL:
                    return v == value;
                case AttrConditionCompute.GREATER:
                    return v > value;
                case AttrConditionCompute.LESS:
                    return v < value;
                case AttrConditionCompute.GREATER_EQUAL:
                    return v >= value;
                case AttrConditionCompute.LESS_EQUAL:
                    return v <= value;
                case AttrConditionCompute.MULTIPLE:
                    return v % value == 0;
                case AttrConditionCompute.EQUAL_VAR:
                    return v == vars[value];
                case AttrConditionCompute.GREATER_VAR:
                    return v > vars[value];
                case AttrConditionCompute.LESS_VAR:
                    return v < vars[value];
                case AttrConditionCompute.GREATER_EQUAL_VAR:
                    return v >= vars[value];
                case AttrConditionCompute.LESS_EQUAL_VAR:
                    return v <= vars[value];
                case AttrConditionCompute.MULTIPLE_VAR:
                    return v % vars[value] == 0;
                case AttrConditionCompute.NO_EQUAL_VAR:
                    return v != vars[value];
                case AttrConditionCompute.NO_EQUAL:
                    return v != value;
            }

            return false;
        }

        public override string ToString()
        {
            return string.Format("AttrCondition: index->{0} compute->{1} value->{2}", index, compute, value);
        }

        public object[] ToObject()
        {
            return new object[] { index, compute, value };
        }
    }

    [Serializable]
    public class AttrConditionList
    {
        public AttrCondition[] attrConditions;

        public AttrConditionList(object[] objects)
        {
            if (objects != null)
            {
                attrConditions = new AttrCondition[objects.Length];
                for (var i = 0; i < objects.Length; i++) attrConditions[i] = new AttrCondition((object[])objects[i]);
            }
            else
            {
                attrConditions = new AttrCondition[] { };
            }
        }

        public override string ToString()
        {
            var s = "";
            for (var i = 0; i < attrConditions.Length; i++)
                s += string.Format(" index->{0} value->{1}", i, attrConditions[i]);
            return string.Format("AttrConditionList: {0}", s);
        }

        public object[] ToObject()
        {
            var result = new object[attrConditions.Length];
            for (var i = 0; i < attrConditions.Length; i++) result[i] = attrConditions[i].ToObject();
            return result;
        }
    }

    public enum ATTR_COMPUTE : byte
    {
        INDEX,
        ACTION,
        TARGET,
        VALUE
    }

    public enum AttrComputeAction : byte
    {
        Add = 0,
        Subtract = 1,
        Multiply = 2,
        Divide = 3,
        AddPercent = 4,
        SubtractPercent = 5,
        Percent = 6,
        Min = 7,
        Max = 8,
        Equal = 9,
        AddRandomPercent = 10,
        SubtractRandomPercent = 11,
        RandomPercent = 12,
        Lerp = 13
    }

    [Serializable]
    public class AttrCompute
    {
        public byte index;
        [SerializeField] public AttrComputeAction action;
        public byte target;
        [SerializeField] public int value;

        public AttrCompute(object[] objects)
        {
            index = (byte)objects[(byte)ATTR_COMPUTE.INDEX];
            action = (AttrComputeAction)Convert.ToByte(objects[(byte)ATTR_COMPUTE.ACTION]);
            target = Convert.ToByte(objects[(byte)ATTR_COMPUTE.TARGET]);
            value = Convert.ToInt32(objects[(byte)ATTR_COMPUTE.VALUE]);
        }

        public override string ToString()
        {
            return string.Format("AttrCompute: index->{0} action->{1} target->{2} value->{3}", index, action, target,
                value);
        }

        public object[] ToObject()
        {
            return new object[] { index, action, value };
        }

        public int Compute(int source, int other, Random random)
        {
            // Debug.LogError("compute:"+source+"->"+other);
            switch (action)
            {
                case AttrComputeAction.Add:
                    return source + other;
                case AttrComputeAction.Subtract:
                    return source - other;
                case AttrComputeAction.Multiply:
                    return source * other;
                case AttrComputeAction.Divide:
                    return other == 0 ? 0 : FixedTools.Divide(source, other);
                case AttrComputeAction.AddPercent:
                    return FixedTools.AddPercent(source, other);
                case AttrComputeAction.SubtractPercent:
                    return FixedTools.SubtractPercent(source, other);
                case AttrComputeAction.Percent:
                    return FixedTools.Percent(source, other);
                case AttrComputeAction.Min:
                    return Math.Min(source, other);
                case AttrComputeAction.Max:
                    return Math.Max(source, other);
                case AttrComputeAction.Equal:
                    return other;
                // case AttrComputeAction.AddRandomPercent:
                //     return source * (100 + random.Next(other)) / 100;
                // case AttrComputeAction.SubtractRandomPercent:
                //     return source * (100 - random.Next(other)) / 100;
                // case AttrComputeAction.RandomPercent:
                //     return source * (100 + random.Next(other * 2) - other) / 100;
                // case AttrComputeAction.Lerp:
                //     var r = (float)random.Next(1, 100) / 100;
                //     return Convert.ToInt32(Mathf.Lerp(source, other, r));
            }

            return source;
        }
    }

    [Serializable]
    public class AttrComputeList
    {
        public AttrCompute[] attrComputes;

        public AttrComputeList(object[] objects)
        {
            if (objects != null)
            {
                attrComputes = new AttrCompute[objects.Length];
                for (var i = 0; i < objects.Length; i++) attrComputes[i] = new AttrCompute((object[])objects[i]);
            }
            else
            {
                attrComputes = new AttrCompute[] { };
            }
        }

        public override string ToString()
        {
            var s = "";
            for (var i = 0; i < attrComputes.Length; i++)
                s += string.Format(" index->{0} value->{1}", i, attrComputes[i]);
            return string.Format("AttrComputeList: {0}", s);
        }

        public object[] ToObject()
        {
            var result = new object[attrComputes.Length];
            for (var i = 0; i < attrComputes.Length; i++) result[i] = attrComputes[i].ToObject();
            return result;
        }
    }

    public enum ATTR_LOGIC : byte
    {
        PARAM,
        CONDITION,
        COMPUTE
    }

    [Serializable]
    public class AttrLogic
    {
        public AttrConditionList conditionList;
        public AttrComputeList computeList;
        public int[] param;
        public bool init;

        public AttrLogic(object[] objects)
        {
            if (objects[(byte)ATTR_LOGIC.PARAM] != null)
            {
                var tmp = (object[])objects[(byte)ATTR_LOGIC.PARAM];
                param = new int[tmp.Length];
                for (var i = 0; i < tmp.Length; i++) param[i] = Convert.ToInt32(tmp[i]);
            }
            else
            {
                param = new int[0];
            }

            if (objects[(byte)ATTR_LOGIC.CONDITION] != null)
                conditionList = new AttrConditionList((object[])objects[(byte)ATTR_LOGIC.CONDITION]);
            if (objects[(byte)ATTR_LOGIC.CONDITION] != null)
                computeList = new AttrComputeList((object[])objects[(byte)ATTR_LOGIC.COMPUTE]);
        }

        public override string ToString()
        {
            return string.Format("AttrLogic: conditionList->{0} computeList->{1} ", conditionList, computeList);
        }

        public object[] ToObject()
        {
            return new object[] { param, conditionList, computeList };
        }
    }

    [Serializable]
    public class AttrLogicList
    {
        public AttrLogic[] attrLogics;

        public AttrLogicList(object[] objects)
        {
            if (objects != null)
            {
                attrLogics = new AttrLogic[objects.Length];
                for (var i = 0; i < objects.Length; i++) attrLogics[i] = new AttrLogic((object[])objects[i]);
            }
            else
            {
                attrLogics = new AttrLogic[] { };
            }
        }

        public override string ToString()
        {
            var s = "";
            for (var i = 0; i < attrLogics.Length; i++) s += string.Format(" index->{0} value->{1}", i, attrLogics[i]);
            return string.Format("AttrLogicList: {0}", s);
        }

        public object[] ToObject()
        {
            var result = new object[attrLogics.Length];
            for (var i = 0; i < attrLogics.Length; i++) result[i] = attrLogics[i].ToObject();
            return result;
        }
    }

    [Serializable]
    public class AttrEvent
    {
        public AttrAdditionList list;

        public AttrEvent(object[] objects)
        {
            list = new AttrAdditionList(objects);
        }

        public override string ToString()
        {
            return string.Format("AttrEvent: list->{0} ", list);
        }

        public object[] ToObject()
        {
            return new object[] { list };
        }
    }

    [Serializable]
    public class AttrEventList
    {
        public AttrEvent[] attrEvents;

        public AttrEventList(object[] objects)
        {
            if (objects != null)
            {
                attrEvents = new AttrEvent[objects.Length];
                for (var i = 0; i < objects.Length; i++) attrEvents[i] = new AttrEvent((object[])objects[i]);
            }
            else
            {
                attrEvents = new AttrEvent[] { };
            }
        }

        public AttrEvent Get(int index)
        {
            if (attrEvents.Length > index) return attrEvents[index];

            return null;
        }

        public override string ToString()
        {
            var s = "";
            for (var i = 0; i < attrEvents.Length; i++) s += string.Format(" index->{0} value->{1}", i, attrEvents[i]);
            return string.Format("AttrAdditionList: {0}", s);
        }

        public object[] ToObject()
        {
            var result = new object[attrEvents.Length];
            for (var i = 0; i < attrEvents.Length; i++) result[i] = attrEvents[i].ToObject();
            return result;
        }
    }

    public enum ATTR_ADDITION : byte
    {
        INDEX,
        PARAM
    }

    [Serializable]
    public class AttrAddition
    {
        [SelectRef("attr_logic_group")] public int groupIndex;
        public int[] param;

        public AttrAddition(object[] objects)
        {
            groupIndex = Convert.ToInt32(objects[(byte)ATTR_ADDITION.INDEX]);
            if (objects[(byte)ATTR_ADDITION.PARAM] != null)
            {
                var tmp = (object[])objects[(byte)ATTR_ADDITION.PARAM];
                param = new int[tmp.Length];
                for (var i = 0; i < tmp.Length; i++) param[i] = Convert.ToInt32(tmp[i]);
            }
            else
            {
                param = new int[0];
            }
        }

        public override string ToString()
        {
            return string.Format("AttrAddition: groupIndex->{0}", groupIndex);
        }

        public object[] ToObject()
        {
            return new object[] { groupIndex };
        }
    }

    [Serializable]
    public class AttrAdditionList
    {
        public AttrAddition[] attrAdditions;

        public AttrAdditionList(object[] objects)
        {
            if (objects != null)
            {
                attrAdditions = new AttrAddition[objects.Length];
                for (var i = 0; i < objects.Length; i++) attrAdditions[i] = new AttrAddition((object[])objects[i]);
            }
            else
            {
                attrAdditions = new AttrAddition[] { };
            }
        }

        public override string ToString()
        {
            var s = "";
            for (var i = 0; i < attrAdditions.Length; i++)
                s += string.Format(" index->{0} value->{1}", i, attrAdditions[i]);
            return string.Format("AttrAdditionList: {0}", s);
        }

        public object[] ToObject()
        {
            var result = new object[attrAdditions.Length];
            for (var i = 0; i < attrAdditions.Length; i++) result[i] = attrAdditions[i].ToObject();
            return result;
        }
    }

    public enum ATTR_EFFECT : byte
    {
        INDEX,
        VALUE
    }

    [Serializable]
    public class AttrEffect
    {
        [SelectRef("attr")] public byte index;
        [SerializeField] public int value;

        public AttrEffect(object[] objects)
        {
            index = (byte)objects[(byte)ATTR_EFFECT.INDEX];
            value = Convert.ToInt32(objects[(byte)ATTR_EFFECT.VALUE]);
        }

        public override string ToString()
        {
            return string.Format("AttrEffect: index->{0} value->{1}", index, value);
        }

        public object[] ToObject()
        {
            return new object[] { index, value };
        }
    }

    [Serializable]
    public class AttrEffectList
    {
        public AttrEffect[] attrEffects;

        public AttrEffectList(object[] objects)
        {
            if (objects != null)
            {
                attrEffects = new AttrEffect[objects.Length];
                for (var i = 0; i < objects.Length; i++) attrEffects[i] = new AttrEffect((object[])objects[i]);
            }
            else
            {
                attrEffects = new AttrEffect[] { };
            }
        }

        public void Effect(ObjectAttrInf attrData, int b = 1)
        {
            foreach (var effect in attrEffects)
            {
                var index = attrData.Manager().AttrIndex(effect.index);
                attrData.SetWithIndex(index, attrData.GetWithIndex(index) + effect.value * b);
            }
        }

        public override string ToString()
        {
            var s = "";
            for (var i = 0; i < attrEffects.Length; i++)
                s += string.Format(" index->{0} value->{1}", i, attrEffects[i]);
            return string.Format("AttrEffectList: {0}", s);
        }

        public object[] ToObject()
        {
            var result = new object[attrEffects.Length];
            for (var i = 0; i < attrEffects.Length; i++) result[i] = attrEffects[i].ToObject();
            return result;
        }
    }

    public enum BUFF
    {
        ID,
        EFFECT,
        INTERVAL_TIME,
        SUSTAINED_TIME,
        OVERLYING,
        ATTR_EFFECT,
        OPEN_EVENT,
        ATTR_EVENT,
        CAST_ATTR,
        TARGET_ATTR,
        DEFINE,
        DEFINE_LEVEL,
        GROUP,
        IS_DEATH_CLEAR,
        IS_SAVE,
        IS_RESET,
        CAST_DEFINE,
        TARGET_DEFINE,
        DEPEND_EFFECT
    }

    [Serializable]
    public class Buff
    {
        public RefInfo refInfo;
        public string effect;
        public int intervalTime;
        public int sustainedTime;
        public bool overlying;
        public bool openEvent;
        public AttrEffectList attrEffect;
        public AttrEventList attrEvent;
        public AttrEffectList casterAttr;
        public AttrEffectList targetAttr;
        public int define;
        public int defineLevel;
        public int[] group;
        public bool isDeathClear;
        public bool isSave;
        public bool isReset;
        public byte casterDefine;
        public byte targetDefine;
        public StrategyEffect DependEffect;

        public Buff(object[] objects, AttrManager manager)
        {
            refInfo = new RefInfo();
            refInfo.id = Convert.ToInt32(objects[(byte)BUFF.ID]);
            effect = (string)objects[(byte)BUFF.EFFECT];
            intervalTime = Convert.ToInt32(objects[(byte)BUFF.INTERVAL_TIME]);
            sustainedTime = Convert.ToInt32(objects[(byte)BUFF.SUSTAINED_TIME]);
            overlying = Convert.ToBoolean(objects[(byte)BUFF.OVERLYING]);
            attrEffect = new AttrEffectList((object[])objects[(byte)BUFF.ATTR_EFFECT]);
            openEvent = Convert.ToBoolean(objects[(byte)BUFF.OPEN_EVENT]);
            attrEvent = new AttrEventList((object[])objects[(byte)BUFF.ATTR_EVENT]);
            casterAttr = new AttrEffectList((object[])objects[(byte)BUFF.CAST_ATTR]);
            targetAttr = new AttrEffectList((object[])objects[(byte)BUFF.TARGET_ATTR]);
            define = Convert.ToInt32(objects[(byte)BUFF.DEFINE]);
            defineLevel = Convert.ToInt32(objects[(byte)BUFF.DEFINE_LEVEL]);
            if (objects[(byte)BUFF.GROUP] != null)
            {
                var g = (object[])objects[(byte)BUFF.GROUP];
                group = new int[g.Length];
                for (var i = 0; i < g.Length; i++) group[i] = Convert.ToInt32(g[i]);
            }
            else
            {
                group = new int[0];
            }

            isDeathClear = Convert.ToBoolean(objects[(byte)BUFF.IS_DEATH_CLEAR]);
            isSave = Convert.ToBoolean(objects[(byte)BUFF.IS_SAVE]);
            isReset = Convert.ToBoolean(objects[(byte)BUFF.IS_RESET]);
            casterDefine = Convert.ToByte(objects[(byte)BUFF.CAST_DEFINE]);
            targetDefine = Convert.ToByte(objects[(byte)BUFF.TARGET_DEFINE]);
            DependEffect = new StrategyEffect(objects[(byte)BUFF.DEPEND_EFFECT], manager);
        }

        public override string ToString()
        {
            return string.Format("Buff:{0} effect->{1} intervalTime->{2} sustainedTime->{3}" +
                                 " attrEffect->{4} attrEvent->{5} openEvent->{6} casterAttr->{7} targetAttr->{8} define->{9} defineLevel->{10}",
                refInfo, effect, intervalTime, sustainedTime, attrEffect, attrEvent, openEvent, casterAttr, targetAttr, define, defineLevel);
        }

        public object[] ToObject()
        {
            return new object[]
            {
                refInfo.id, effect, intervalTime, sustainedTime, overlying, attrEffect.ToObject(), openEvent,
                attrEvent.ToObject(), casterAttr.ToObject(), targetAttr.ToObject()
            };
        }
    }

    public class BuffFormatter : SerializeFormatter
    {
        internal static readonly BuffFormatter instance = new();

        public object Deserialize(byte[] stream)
        {
            var id = MessagePackSerializer.Deserialize<int>(stream);
            //            var id = BitConverter.ToInt32(stream, 0);
            return EngineService.single.GetBuff(id);
        }

        public byte[] Serialize(object customobject)
        {
            var buff = (Buff)customobject;
            return MessagePackSerializer.Serialize(buff.refInfo.id);
            //            return BitConverter.GetBytes(buff.id);
        }
    }

    public enum SKILL
    {
        ID,
        EFFECT,
        DISTANCE,
        RANGE,
        SPEED,
        ANGLE,
        NUMBER,
        EASE,
        READY_TIME,
        CAST_TIME,
        COOL_TIME,
        INTERVAL_TIME,
        SUSTAINED_TIME,
        HANDLE_TYPE,
        TARGET_RELATION,
        TARGET_STATUS,
        CAST_NEED,
        SKILL_PLAN,
        CAST_TYPE,
        CALL,
        CALL_NUMBER,
        OPEN_EVENT,
        ATTR_EVENT,
        CAST_ATTR,
        TARGET_ATTR
    }


    [Serializable]
    public class Skill
    {
        public RefInfo refInfo;
        public string effect;
        public int distance;
        public int range;
        public int speed;
        public int angle;
        public int number;
        public float readyTime;
        public float castTime;
        public float coolTime;
        public float intervalTime;
        public float sustainedTime;
        public EaseType ease;
        public SkillHandleType handleType;
        public TargetRelation targetRelation;
        public TargetStatus targetStatus;
        public SkillCastNeed caseNeed;
        public int skillPlan;
        public SkillCastType castType;
        [SelectRef("object")] public int call;
        public int callNumber;
        public bool openEvent;
        public AttrEventList attrEvent;
        public AttrEffectList casterAttr;
        public AttrEffectList targetAttr;

        public Skill(object[] objects)
        {
            refInfo = new RefInfo();
            refInfo.id = Convert.ToInt32(objects[(byte)SKILL.ID]);
            effect = (string)objects[(byte)SKILL.EFFECT];
            distance = Convert.ToInt32(objects[(byte)SKILL.DISTANCE]);
            range = Convert.ToInt32(objects[(byte)SKILL.RANGE]);
            speed = Convert.ToInt32(objects[(byte)SKILL.SPEED]);
            angle = Convert.ToInt32(objects[(byte)SKILL.ANGLE]);
            number = Convert.ToInt32(objects[(byte)SKILL.NUMBER]);
            ease = (EaseType)Convert.ToInt32(objects[(byte)SKILL.EASE]);
            readyTime = Convert.ToSingle(objects[(byte)SKILL.READY_TIME]);
            castTime = Convert.ToSingle(objects[(byte)SKILL.CAST_TIME]);
            coolTime = Convert.ToSingle(objects[(byte)SKILL.COOL_TIME]);
            intervalTime = Convert.ToSingle(objects[(byte)SKILL.INTERVAL_TIME]);
            sustainedTime = Convert.ToSingle(objects[(byte)SKILL.SUSTAINED_TIME]);
            handleType = (SkillHandleType)Convert.ToInt32(objects[(byte)SKILL.HANDLE_TYPE]);
            targetRelation = (TargetRelation)Convert.ToInt32(objects[(byte)SKILL.TARGET_RELATION]);
            targetStatus = (TargetStatus)Convert.ToInt32(objects[(byte)SKILL.TARGET_STATUS]);
            caseNeed = (SkillCastNeed)Convert.ToInt32(objects[(byte)SKILL.CAST_NEED]);
            skillPlan = Convert.ToInt32(objects[(byte)SKILL.SKILL_PLAN]);
            castType = (SkillCastType)Convert.ToInt32(objects[(byte)SKILL.CAST_TYPE]);
            call = Convert.ToInt32(objects[(byte)SKILL.CALL]);
            callNumber = Convert.ToInt32(objects[(byte)SKILL.CALL_NUMBER]);
            openEvent = Convert.ToBoolean(objects[(byte)SKILL.OPEN_EVENT]);
            attrEvent = new AttrEventList((object[])objects[(byte)SKILL.ATTR_EVENT]);
            casterAttr = new AttrEffectList((object[])objects[(byte)SKILL.CAST_ATTR]);
            targetAttr = new AttrEffectList((object[])objects[(byte)SKILL.TARGET_ATTR]);
        }

        public override string ToString()
        {
            return string.Format(
                "Skill:{0} effect->{1} distance->{2} range->{3} speed->{4} angle->{5} number->{6} ease->{7} " +
                "readyTime->{8} castTime->{9} coolTime->{10} intervalTime->{11} sustainedTime->{12} handleType->{13} targetRelation->{14} targetStatus->{15} " +
                "skillPlan->{16} caseNeed->{17} castType->{18} call->{19} callNumber->{20} openEvent->{21} attrEvent->{22} casterAttr->{23} targetAttr->{24}",
                refInfo, effect,
                distance, range, speed, angle, number, ease, readyTime, castTime, coolTime, intervalTime, sustainedTime,
                handleType, targetRelation,
                targetStatus, skillPlan, caseNeed, castType, call, callNumber, openEvent, attrEvent, casterAttr,
                targetAttr);
        }

        public object[] ToObject()
        {
            return new object[]
            {
                refInfo.id, effect, distance, range, speed, angle, number, ease,
                readyTime, castTime, coolTime, intervalTime, sustainedTime,
                handleType, targetRelation, targetStatus, caseNeed, skillPlan, castType,
                call, callNumber, openEvent, attrEvent.ToObject(), casterAttr.ToObject(), targetAttr.ToObject()
            };
        }
    }

    public class SkillFormatter : SerializeFormatter
    {
        internal static readonly SkillFormatter instance = new();

        public object Deserialize(byte[] stream)
        {
            var id = MessagePackSerializer.Deserialize<int>(stream);
            //            var id = BitConverter.ToInt32(stream, 0);
            return EngineService.single.GetSkill(id);
        }

        public byte[] Serialize(object customobject)
        {
            var skill = (Skill)customobject;
            return MessagePackSerializer.Serialize(skill.refInfo.id);
            //            return BitConverter.GetBytes(skill.id);
        }
    }

    public interface Effect
    {
        Entity GetEntity();
    }

    public interface ParticleEffect : Effect
    {
        void Play();
        void Stop();
    }

    public interface BaseEffect : Effect
    {
        void Show();
        void Hide();
    }

    public interface SwitchEffect : Effect
    {
        void Open();
        void Open(GameObject origin);
        void Close();
    }

    public interface SprayEffect : SwitchEffect
    {
        void Move(Vector3 position);
        void Move(Vector3 position, Quaternion rotation);
    }

    public interface RayEffect : Effect
    {
        void Open();
        void Close();
        void Cast(GameObject origin, float distance);
        void Cast(GameObject origin, Vector3 end);
        void Cast(GameObject origin, RayHitData hit);
    }

    public interface ColliderEffect : Effect
    {
        void Open();
        void Close();
        void Size(float radius);
        void Hit(RayHitData hit);
    }

    public interface LaunchEffect : Effect
    {
        void Launch(Vector3 position, Quaternion rotation);
        void Hit(RayHitData hit);
        void Move(Vector3 position);
        void Move(Vector3 position, Quaternion rotation);
        void Clear();
    }

    public interface PowerLaunchEffect : LaunchEffect
    {
        void Ready(Vector3 position, Quaternion rotation);
        void Size(float size);
    }

    public enum SkillHandleType : byte
    {
        Default,
        Switch,
        Repeat,
        Ready,
        Sustained
    }

    public enum SkillCastStatus : byte
    {
        Start,
        End,
        Ready,
        Stop,
        Cancel
    }

    public enum SkillCastNeed : byte
    {
        None = 0,
        Target = 1,
        Position = 2,
        MultipleTarget = 3,
        MultiplePosition = 4,
        NoneOrTarget = 5
    }

    public enum SkillCastType : byte
    {
        Now = 0,
        Ready = 1,
        Sustained = 2,
        ReadyAndSustained = 3
    }

    public enum TargetRelation : byte
    {
        None = 0,
        Self = 1,
        Partner = 2,
        Enemy = 3
    }

    public enum TargetStatus : byte
    {
        Live = 0,
        Die = 1
    }

    public enum ObjectControl : byte
    {
        Base = 0,
        Player = 1,
        OtherPlayer = 2,
        Ai = 3,
        AiPlayer = 4
    }

    public enum ObjectCollider : byte
    {
        Empty = 0,
        Box = 1,
        Sphere = 2,
        Capsule = 3
    }
}